package com.atguigu.yyj.aspect;

import com.atguigu.yyj.annotation.Cacheable;
import com.atguigu.yyj.constant.CacheAbleConstant;
import com.atguigu.yyj.service.CacheOpsService;
import com.fasterxml.jackson.core.type.TypeReference;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
 * @Author：yyj
 * @Package：com.atguigu.tingshu.search.aspect
 * @Project：tingshu_parent240829
 * @name：CacheAspect
 * @Date：2025/2/15 20:09
 * @Filename：CacheAspect
 */
//@Component
@Aspect
public class CacheAspect {
    @Autowired
    private RBloomFilter rBloomFilter;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private CacheOpsService cacheOpsService;
    @Around(value = "@annotation(com.atguigu.yyj.annotation.Cacheable)")
    public Object checkCache(ProceedingJoinPoint pjp) throws Throwable {

        //Object[] args = pjp.getArgs();
        Method method = getMethod(pjp);
        //1.定义变量
        // 1.定义变量
        // 获取目标方法的注解对象
        Cacheable annotation = getMethodAnnotation(pjp, Cacheable.class);
        // 得到缓存key表达式
        String cacheKeyExpression = annotation.cacheKey();
        // 得到缓存key
        String cacheKey = computeCacheKey(cacheKeyExpression, pjp, String.class);
        // 得到分布式锁key表达式
        String lockKeyExpression = annotation.distroLockKey();
        // 得到分布式锁的key
        String lockKey = computeCacheKey(lockKeyExpression, pjp, String.class);
        // 得到分布式布隆key表达式
        String bloomKeyExpression = annotation.distroBloomKey();
        // 得到分布式布隆的key
        Long bloomKey = computeCacheKey(bloomKeyExpression, pjp, Long.class);
        //操作缓存 查询缓存 查询数据 放到缓存

        // 2.查询分布式布隆过滤器（缓存穿透的随机值攻击）
        boolean isUseBloom = annotation.distroBloomSwitch();
        if (isUseBloom) {
            boolean bloomContainFlag = rBloomFilter.contains(bloomKey);
            // 2.1 布隆说没有
            if (!bloomContainFlag) {
                return null;
            }
        }
        //布隆有
        //3.查询缓存
        Object dataFromCache = cacheOpsService.getDataFromCache(cacheKey, new TypeReference<Object>() {
            @Override
            public Type getType() {
                return method.getGenericReturnType();
            }
        });
        // 3.1 缓存命中(反序列化成功)
        if (dataFromCache != null) {
            return dataFromCache;
        }

        // 3.2 缓存未命中
        // 4.获取分布式锁
        // 4.1 获取锁对象
        boolean isUseDistLock = annotation.distroLockSwitch();
        if (isUseDistLock){
            Object objectFromDb = pjp.proceed(); // 查询数据库
            // 4.3.2 同步数据到缓存
            cacheOpsService.saveDataToCache(cacheKey, objectFromDb);
            return objectFromDb;
        }
        RLock lock = redissonClient.getLock(lockKey);
        //加锁(解决缓存击穿)
        boolean acquireLockFlag = lock.tryLock();
        // 4.3 抢到了锁
        if (acquireLockFlag) {
            // 4.3.1 回源
            try {
                Object objectFromDb = pjp.proceed(); // 查询数据库
                // 4.3.2 同步数据到缓存
                 cacheOpsService.saveDataToCache(cacheKey, objectFromDb);
                return objectFromDb;
            } finally {
                // 4.3.3 释放锁
                lock.unlock();
            }

        } else {
            // 4.4 没有抢到锁（同步数据的时间）
            try {
                Thread.sleep(CacheAbleConstant.SYNC_DATA_TIME);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return cacheOpsService.getDataFromCache(cacheKey, new TypeReference<Object>() {
                @Override
                public Type getType() {
                    return method.getGenericReturnType();
                }
            });
        }

    }
    private static Method getMethod(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        return method;

    }
    /**
     * 获取目标方法的任意注解对象
     *
     * @param pjp
     * @param tClass
     * @param <T>
     * @return
     */
    private static <T extends Annotation> T getMethodAnnotation(ProceedingJoinPoint pjp, Class<T> tClass) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        T annotation = method.getAnnotation(tClass);
        return annotation;
    }

    /**
     * 计算缓存key
     *
     * @param cacheKeyExpression
     * @param pjp
     * @return
     */
    private <T> T computeCacheKey(String cacheKeyExpression, ProceedingJoinPoint pjp, Class<T> valueType) {


        // 1. 创建解析表达式的对象
        SpelExpressionParser spelExpressionParser = new SpelExpressionParser();

        // 2.创建解析上下文对象
        TemplateParserContext templateParserContext = new TemplateParserContext();

        // 3.创建一个计算表达式对象
        StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        standardEvaluationContext.setVariable("args", pjp.getArgs());


        Expression expression = spelExpressionParser.parseExpression(cacheKeyExpression, templateParserContext);
        T value = expression.getValue(standardEvaluationContext, valueType);
        return value;
    }

}